#!/bin/sh
#
# The fig2eps script converts fig files to eps. By default, a latex + dvips
# run is used to include the special text from the fig file in the eps file.
# Alternatively, fig2eps can generate separate latex code to overlay the eps
# file with the special text in a document.
#
# Copyright (c) 2003,2004,2005,2006,2007,2008,2009,2010 Wouter Kager
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

program=`basename $0`
version=2010/09/01
packages=
class=article
sp2pt=65536.00
gsopts="-q -dSAFER -dNOPAUSE -dBATCH"
fixbb=n
force=n
debug=n
csub=
fsub=
fres=
gsres=-r600
mode=eps

echo "$program $version by Wouter Kager"
echo

# Scan command line options.
while getopts :bBc:Cd:DfFkp:r:tT optionkey $*; do
	case $optionkey in
		b)	sp2pt=65781.76 ;;
		B)	fixbb=y ;;
		c)	class=$class]$OPTARG ;;
		C)  csub="&"
			packages=${packages}color, ;;
		d)	if [ $OPTARG -gt 0 ]; then
				gsres=-r$OPTARG
			else
				gsres=
			fi ;;	
		D)	gsres= ;;
		f)	force=y ;;
		F)	fsub="&\\\\selectfont" ;;
		k)	debug=y ;;
		p)	packages=$packages$OPTARG, ;;
		r)	fres="-D $OPTARG" ;;
		t)	mode=tex ;;
		T)	mode=texfile ;;
		:)	echo "$program: the option -$OPTARG requires an argument!"
			echo "$program: run $program without arguments for help"
			exit 1 ;;
		?)	echo "$program: the option -$OPTARG is illegal!"
			echo "$program: run $program without arguments for help"
			exit 1 ;;
	esac
done

shift `expr $OPTIND - 1`

# Check if there are any input files.
if [ ${#} -eq 0 ]; then
	cat <<-EOF
		Usage: $program [options] figfile(s)

		Common options for all output modes:
		 -B            correct the Bounding Box (when dvips fails)
		 -C            turn on color (include latex color package)
		 -d res        set distiller resolution (dpi), default=600
		 -D or -d 0    suppress use of gs distiller for eps output
		 -f            force files to be overwritten if they exist
		 -F            use the font size information from fig file
		 -k            keep temporary files for debugging purposes

		Options for default output mode (embedded special text):
		 -c class      specify document class  (default = article)
		 -p packages   specify packages (graphicx is always added)
		 -r res        specify font resolution to be used by dvips

		Options for other output modes:
		 -t            to generate eps file with separate tex code
		 -T            to generate eps file with separate tex file
		 -b            assume that \unitlength=1bp, instead of 1pt

		Packages must be specified as a comma-separated list, with
		options for a particular package written directly in front
		of the package name between square brackets. Likewise, you
		can specify class options between square brackets directly
		in front of the class name. In this case you may leave out
		the class name to use the default article class.
		
		Example: $program -c [12pt] -p txfonts,[one,two]mysty *.fig
		EOF
	exit 0
fi

# This tricky code parses the class and packages arguments.
for field in `echo $class | tr ] " "`
do
	if [ `echo $field | cut -c1` = "[" ]; then
		options=$field]
	else
		class={$field}
	fi
done

class=\\documentclass$options$class

tmp=`echo $packages | tr ] " "`
packages=\\usepackage
options=

for field in $tmp
do
	for subfield in `echo $field | tr , " "`
	do
		if [ `echo $subfield | cut -c1` = "[" ]; then
			options=$subfield
		else
			if [ -z "$options" ]; then
				packages=$packages{$subfield}\\usepackage
			else
				options=$options,$subfield
			fi
		fi
	done
	if [ -n "$options" ]; then
		packages=$packages$options]
		options=
	fi
done

packages=$packages{graphicx}

#--------------------------- Function definitions ---------------------------

# latex_code generates (human-readable) latex code from the file $base.fig
# which includes the figure and overlays it with the special text.
latex_code ()
{
	if [ $foundspecial = yes ]; then
	fig2dev -L pstex_t -F "$base.fig" 2> /dev/null |
	sed -n '/\\setlength{\\unitlength}/ {
			s/sp//
			s/[{}]/ /gp
		 }
		 /\\begin{picture}/ s/[(,)]/ /gp
		 /\\put/ {
			s/\\SetFigFont[a-zA-Z]*{[^}]*}{[^}]*}/'$fsub'/
			s/\\SetFigFont[a-zA-Z]*/\\fontsize/
			s/\\smash{*/\\smash{/
		 	s/\\color\[.*\]{[^}]*}/'$csub'/
			s/}*%*$/}/
			s/(/ /
			s/,/ /
			s/)/ /p
			s/\\.//g
			s/[{}]/& /g
			s/[^{}]/ /gp
			s/[^}]/ /gp
		 }' |
	awk '/unitlength/ {unit=$3/'$sp2pt'}
		 /begin{picture}/ {x=$2; y=$3; shiftx=$4; shifty=$5;
			printf "%s(%.0f,%.0f)\n",$1,x*unit,y*unit;
			printf "\\put(0,0){\\includegraphics{'"$base"'}}\n"}
		 /put/ {x=$2; y=$3; x-=shiftx; y-=shifty;
			printf "\\put(%.0f,%.0f)",x*unit,y*unit;
			for (i=4;i<NF;i++) printf "%s ",$i; printf "%s",$NF;
			getline; lbraces=NF; getline; lbraces-=2*NF;
			for (i=1;i<lbraces;i++) printf "}"; print "}"}
		 END {print "\\end{picture}"}'
	else
		echo "\includegraphics{$base}"
	fi
}

# latex_document creates a latex document from $base.fig.
latex_document ()
{
	cat <<-EOF
		$class$packages
		\parindent=0pt\oddsidemargin=0pt\evensidemargin=0pt%
		\topmargin=0pt\headheight=0pt\headsep=0pt%
		\hoffset=0pt\voffset=0pt\pagestyle{empty}%
		\begin{document}
		EOF
	latex_code
	cat <<-EOF
		\end{document}
		EOF
}

# find_bbox scans $1 for the bounding box.
find_bbox ()
{
	set `grep '^%%BoundingBox:' "$1" | head -1`

	wd=`expr $4 - $2`
	ht=`expr $5 - $3`
}

# distill generates a distilled or stripped version of $1.
distill ()
{
	if [ $fixbb = y ]; then
		bbox=`gs $gsopts -sDEVICE=bbox "$1" 2>&1 1>/dev/null | head -1`
	else
		bbox=`grep '^%%BoundingBox:' "$1" | head -1`
	fi

	if [ -n "$gsres" ]; then
		log=`gs $gsopts -sDEVICE=epswrite -sOutputFile=$tmp.eps $gsres \
			-f "$1" 2>/dev/null`
		check_error ghostscript

		sed 's/^%%BoundingBox:.*/'"$bbox"'/
			/^%%HiResBoundingBox:/d' $tmp.eps > "$1"
	else
		cp "$1" $tmp.eps
		sed 's/^%%BoundingBox:.*/'"$bbox"'/
			/^%%HiResBoundingBox:/d
			/^%%Title:/d
			/^%[%!]/p
			/^%.*/d
			s/%.*$//' $tmp.eps > "$1"
	fi
}

# check_file verifies whether $1 exists and is readable.
check_file ()
{
	if [ ! -f "$1" ]; then
		echo "$program: file $1: no such file (skipping)"
		continue
	fi
	if [ ! -r "$1" ]; then
		echo "$program: file $1: not readable (skipping)"
		continue
	fi
}

# check_error checks for and reports errors after running $1.
check_error ()
{
	if [ $? -ne 0 ]; then
		echo [error]
		echo "$program: $1 says:"
		echo
		if [ "$1" = latex ]; then
			awk '/^!/ {print; getline; print}' $tmp.log
		else
			echo "$log"
		fi
		continue
	fi
}

#------------------------- End of function definitions ----------------------

tmp=$program$$
tmpfiles="$tmp.tex $tmp.aux $tmp.dvi $tmp.log $tmp.eps"

# Overwrite existing files only if user agrees.
for j in $tmpfiles
do
	if [ -w $j -a $force = n ]; then
		echo "$program: warning, the file $j exists!"
		printf "$program: should I overwrite it (y/n)? "
		read OK

		if [ "$OK" != y ]; then
			echo "$program: in that case, I can't proceed"
			exit 0
		fi
	fi
done

# Loop through all files specified on the command line.
for file
do

OK=y
echo

base=`echo "$file" | sed 's/\.fig$//'`
check_file "$base.fig"
echo "$program: processing file $base.fig"

# Overwrite existing files only if user agrees.
if [ -w "$base.eps" -a $force = n ]; then
	echo "$program: warning, the file $base.eps exists!"
	printf "$program: should I overwrite it (y/n)? "
	read OK
fi
if [ "$OK" = y -a $mode = texfile -a -w "$base.tex" -a $force = n ]; then
	echo "$program: warning, the file $base.tex exists!"
	printf "$program: should I overwrite it (y/n)? "
	read OK
fi

# Perform conversion or skip file.
if [ "$OK" = y ]; then

	# Look for special text.
	foundspecial=`awk 'BEGIN {s="no"}
		/\\\\001/ {if ($1==4 && ($9/2)%2==1) {s="yes"; exit}}
		END {print s}' "$base.fig"`

	echo "$program: special text found - $foundspecial"
	printf "$program: $base.fig -> $base.eps "

	log=`fig2dev -L pstex "$base.fig" "$base.eps" 2>&1`
	check_error fig2dev

	if [ $foundspecial = yes -a $mode = eps ]; then
		rm -f $tmpfiles
		latex_document > $tmp.tex
		printf "q\n" | latex $tmp.tex > /dev/null 2>&1
		check_error latex

		log=`dvips $fres -q -E -K -Z -o $tmp.eps $tmp.dvi 2>&1`
		check_error dvips

		if [ -n "$log" ]; then
			echo [warning]
			echo "$log"
			printf "$program: $base.fig -> $base.eps "
		fi

		cp $tmp.eps "$base.eps"
	fi

	distill "$base.eps"
	echo [ok]

	find_bbox "$base.eps"
	echo "$program: image size is $wd""bp x $ht""bp"

	if [ $mode = tex ]; then
		echo "$program: latex code follows:"
		echo
		latex_code
	elif [ $mode = texfile ]; then
		echo "$program: use \input{$base.tex} to include image"
		latex_code > "$base.tex"
	fi
else
	echo "$program: file $base.fig skipped [ok]"
fi

done

# Clean up.
if [ $debug = n ]; then
	rm -f $tmpfiles
fi
